#include "Network/PackageManager.h"
#include "Network/ServerRoot.h"
#include "Network/PackageReader.h"
#include "Network/PackageWriter.h"

#include "Network/IPackage.hpp"
#include "Network/FastPackages/ServerInfoPackage.h"
#include "Network/FastPackages/ConnectionRequestPackage.h"

#include "Network/Packages/ClientPackage.h"
#include "Network/Packages/MessagePackage.h"
#include "Network/Packages/PlayerDataPackage.h"

#include "Network/Packages/SubsystemTerrainPackage.h"
#include "Network/Packages/SubsystemWeatherPackage.h"
#include "Network/Packages/SubsystemTimePackage.h"
#include "Network/Packages/SubsystemSkyPackage.h"

#include "Network/Packages/ComponentVitalStatPackage.h"
#include "Network/Packages/ComponentPlayerPackage.h"
#include "Network/Packages/ComponentInventoryPackage.h"
#include "Network/Packages/PickablePackage.h"
#include "Network/Packages/ComponentHealthPackage.h"
#include "Network/Packages/ComponentFurnacePackage.h"
#include "Network/Packages/BlockEditPackage.h"
#include "Network/Packages/ComponentSleepPackage.h"
#include "Network/Packages/SubsystemBodyPackage.h"
#include "Network/Packages/SignBlockPackage.h"
#include "Network/Packages/ComponentClothingPackage.h"
#include "Network/Packages/GroupManagePackage.h"
#include "Network/Packages/MovingBlockPackage.h"


#include "GameEnum.h"
#include "ServerConfigure.h"
#include "Log.h"
#include "GameSingleton.h"


#include "Utils/DynamicMemory.hpp"
#include "Utils/Utils.h"
#include "Engine/GameGuid.h"






// #include "BanManager.h"

namespace PocketSurvival
{
    using namespace Engine;

    PackageManager::PackageManager()
    {
        registerOrReplaceFastPackageHandle(std::make_shared<ServerInfoPackage>());
        registerOrReplaceFastPackageHandle(std::make_shared<ConnectionRequestPackage>());

        // RegisterOrReplacePackageHandle(std::make_shared<ProjectPackage>());

        registerOrReplacePackageHandle(std::make_shared<ClientPackage>());
        registerOrReplacePackageHandle(std::make_shared<MessagePackage>());
        registerOrReplacePackageHandle(std::make_shared<PlayerDataPackage>());
        registerOrReplacePackageHandle(std::make_shared<SubsystemTerrainPackage>());
        registerOrReplacePackageHandle(std::make_shared<SubsystemWeatherPackage>());
        registerOrReplacePackageHandle(std::make_shared<SubsystemTimePackage>());
        registerOrReplacePackageHandle(std::make_shared<SubsystemSkyPackage>());
        
        registerOrReplacePackageHandle(std::make_shared<ComponentVitalStatPackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentPlayerPackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentInventoryPackage>());
        registerOrReplacePackageHandle(std::make_shared<PickablePackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentHealthPackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentFurnacePackage>());
        registerOrReplacePackageHandle(std::make_shared<BlockEditPackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentSleepPackage>());
        
        registerOrReplacePackageHandle(std::make_shared<SubsystemBodyPackage>());
        registerOrReplacePackageHandle(std::make_shared<SignBlockPackage>());
        registerOrReplacePackageHandle(std::make_shared<ComponentClothingPackage>());
        registerOrReplacePackageHandle(std::make_shared<GroupManagePackage>());
        registerOrReplacePackageHandle(std::make_shared<MovingBlockPackage>());
        
    }

    void PackageManager::sendFastPackage(std::shared_ptr<IFastPackage> fastPackage, PacketProperty sendProperty)
    {
        // 即时处理包最大只允许1k的包；
        char comBuff[1024];

        PackageWriter writer(2048);

        // check
        writer.writeUInt8(0x88);
        // 包ID
        writer.writeUInt8(fastPackage->getID());
        // 写入包数据
        fastPackage->writeData(writer);
        // 压缩数据
        uint32_t comSize = Utils::RawDeflateCompresse(writer.getBuffer(), writer.getPosition(), comBuff, sizeof(comBuff));

        writer.setPosition(0);
        writer.writeUInt8((uint8_t)sendProperty);
        writer.writeUInt32(comSize);                // 压缩数据的大小
        writer.write(comBuff, comSize);             // 压缩的数据
        
        GameSingleton::serverRoot->sendTo(writer.getBuffer(), writer.getPosition(), &(fastPackage->endpoint));
    }


    void PackageManager::processFastPackage(net_endpoint *endpoint, const char *buff, uint32_t buffSize, std::shared_ptr<IFastPackage> theFastPackage)
    {
        // 是否需要验证下快速包是否为登录请求包，恶意的登录请求会导致 LiteNetLib 的登录请求没经处理到导致其内存泄漏
        bool needVerifyRequestPackage = true;

        char uncomBuff[1024];
        PackageReader reader(buff, buffSize);

        try
        {
            uint32_t comSize = reader.readUInt32();
            uint32_t uncomSize = Utils::RawInflateDecompresse(reader.getBuffNowPtr(), comSize, uncomBuff, sizeof(uncomBuff));
            if(uncomSize > 0)
            {
                PackageReader packageReader(uncomBuff, uncomSize);
                uint8_t check = packageReader.readUInt8();
                if(check == 0x88)
                {
                    uint8_t fastPackageID = packageReader.readUInt8();
                    if (theFastPackage != nullptr)
                    {
                        theFastPackage->setEndpoint(endpoint);
                        theFastPackage->readData(packageReader);
                        theFastPackage->handle();
                    }
                    else if(baseFastPackages[fastPackageID] != nullptr)
                    {
                        std::shared_ptr<IFastPackage> fastPackage = std::dynamic_pointer_cast<IFastPackage>(baseFastPackages[fastPackageID]->createNewPackage());
                        if(fastPackage == nullptr)
                        {
                            Log::Error(fmt::format("ID:{} 的即时包无法进行转换", fastPackageID), Log::LogType::NET);
                            return;
                        }
                        fastPackage->setEndpoint(endpoint);
                        fastPackage->readData(packageReader);
                        fastPackage->handle();
                    }
                    needVerifyRequestPackage = false;
                }
            }
        }
        catch(const std::exception &ex)
        {
            Log::Error(fmt::format("processFastPackage发生错误 : {}", ex.what()), Log::LogType::NET);
        }

        if (theFastPackage != nullptr && needVerifyRequestPackage == true)
        {
            if (theFastPackage->getID() == (uint8_t)PackageType::ConnectionRequest)
            {
                std::shared_ptr<ConnectionRequestPackage> requestPackage = std::dynamic_pointer_cast<ConnectionRequestPackage>(theFastPackage);
                requestPackage->request->reject();
            }
        }
    }

    // 直接发送数据包
    void PackageManager::sendPackage(std::shared_ptr<IPackage> package)
    {
        PackageWriter packageWriter(4096);
        Utils::DynamicMemory comMemory(4096);

        std::vector<ClientPtr> clientVec;
        GameSingleton::serverRoot->getAllClients(clientVec);
        if(package != nullptr)
        {
            packageWriter.setPosition(0);
            packageWriter.writeUInt8(0x88);
            packageWriter.writeUInt8(package->getID());
            package->writeData(packageWriter);

            uint32_t comSize = Utils::RawDeflateCompresse(packageWriter.getBuffer(), packageWriter.getPosition(), comMemory.getBuffer(), comMemory.getBuffSize());
            if(comSize > 0)
            {
                packageWriter.setPosition(0);
                packageWriter.writeUInt32(comSize);
                packageWriter.write(comMemory.getBuffer(), comSize);
                int32_t index;
                switch (package->sendType)
                {
                case PackageSendType::TARGET:
                    {
                        ClientPtr &client = package->client;
                        if(client != nullptr)
                        {
                            if((uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                            {
                                client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->getChannelNumber(), package->sendMethod);
                            }
                            else
                            {
                                Log::Warn(fmt::format("{} 的状态为 {}, 不够包 {} 所需要的最小状态", client->getAddress(), (uint8_t)client->state, (uint8_t)package->getID()));
                            }
                        }
                    }
                    break;
                case PackageSendType::EXCEPT:
                    for(ClientPtr &client : clientVec)
                    {
                        if(client != package->client && (uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                        {
                            client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->getChannelNumber(), package->sendMethod);
                        }
                    }
                    break;
                case PackageSendType::ALL:
                    for(ClientPtr &client : clientVec)
                    {
                        if((uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                        {
                            client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->getChannelNumber(), package->sendMethod);
                        }
                    }
                    break;
                }
            }
            else
            {
                Log::Warn(fmt::format("sendPackage 数据包压缩错误 : {}", package->getID()));
            }
        }
    }


    // 直接处理客户端发送过来的数据包
    void PackageManager::processPackage(ClientPtr client, const char *buff, uint32_t buffSize)
    {
        char buffer[40960];
        PackageReader reader(buff, buffSize);

        uint8_t packageID = 0;
        try
        {
            uint32_t comSize = reader.readUInt32();
            uint32_t outSize = Utils::RawInflateDecompresse(reader.getBuffNowPtr(), comSize, buffer, sizeof(buffer));
            PackageReader packageReader(buffer, outSize);

            std::vector<std::shared_ptr<IPackage>> packageVec;
            while(packageReader.getPosition() < outSize)
            {
                uint8_t check = packageReader.readUInt8();
                if(check != 0x88)
                {
                    break;
                }
                packageID = packageReader.readUInt8();
                if(basePackages[packageID] != nullptr)
                {
                    std::shared_ptr<IPackage> package = std::dynamic_pointer_cast<IPackage>(basePackages[packageID]->createNewPackage());
                    if(package == nullptr)
                    {
                        throw std::runtime_error("IPackage 无法转换");
                    }

                    package->client = client;
                    package->readData(packageReader);
                    packageVec.push_back(package);
                }
                else
                {
                    std::string errorMess = fmt::format("收到未知ID的包: {}，数据大小{}，位置: {}，数据: {}", packageID, outSize, packageReader.getPosition(), Utils::ToHexString((const uint8_t *)buffer, outSize));
                    Log::Warn(errorMess, Log::LogType::NET);
                    break;
                }
            }
            if(packageVec.size() > 500)
            {
                Log::Info(fmt::format("{} 压包数量超过 500 , 共计压包：{}", client->getAddress(), packageVec.size()));
                if(packageVec.size() >= 800)
                {
                    throw std::runtime_error(fmt::format("禁止压包数量大于等于800个"));
                }
            }
            for(int32_t index = 0; index < packageVec.size(); index++)
            {
                if((uint8_t)client->state >= (uint8_t)packageVec[index]->getMinNeedState())
                {
                    packageVec[index]->handle();
                }
            }
        }
        catch(const std::exception& e)
        {
            client->disconnect("包数据出错");
            Log::Warn(fmt::format("处理包 {} 数据发现错误: {}，已经断开 {} 的连接，地址：{}", packageID, e.what(), client->nickname, client->getAddress()));
        }
    }


    void PackageManager::addClientQueuePackage(ClientPtr client, const char *buff, uint32_t buffSize)
    {
        // char buffer[1024 * 128];

        const uint32_t bufferSize = 1024 * 128;
        char * buffer = new char[bufferSize];
        std::unique_ptr<char> theMemory(buffer);

        PackageReader reader(buff, buffSize);
        uint8_t packageID = 0;

        try
        {
            uint32_t comSize = reader.readUInt32();
            uint32_t outSize = Utils::RawInflateDecompresse(reader.getBuffNowPtr(), comSize, buffer, bufferSize);
            PackageReader packageReader(buffer, outSize);

            while(packageReader.getPosition() < outSize)
            {
                uint8_t check = packageReader.readUInt8();
                if(check != 0x88)
                {
                    break;
                }
                packageID = packageReader.readUInt8();
                if(basePackages[packageID] != nullptr)
                {
                    std::shared_ptr<IPackage> package = std::dynamic_pointer_cast<IPackage>(basePackages[packageID]->createNewPackage());
                    if(package == nullptr)
                    {
                        throw std::runtime_error("IPackage 无法转换");
                    }

                    package->client = client;
                    package->readData(packageReader);

                    client->addWaitHandlePackage(package);
                }
                else
                {
                    std::string errorMess = fmt::format("收到未知ID的包: {}，数据大小{}，位置: {}，数据: {}", packageID, outSize, packageReader.getPosition(), Utils::ToHexString((const uint8_t *)buffer, outSize));
                    Log::Warn(errorMess, Log::LogType::NET);
                    break;
                }
            }
        }
        catch(const std::exception& e)
        {
            client->disconnect("包数据出错");
            Log::Warn(fmt::format("处理包 {} 数据发现错误: {}，已经断开 {} 的连接，地址：{}", packageID, e.what(), client->nickname, client->getAddress()));
        }
    }
    


    void PackageManager::sendQueuePackage()
    {
        try
        {
            PackageWriter packageWriter(4096);
            Utils::DynamicMemory comMemory(4096);
            
            std::shared_ptr<IPackage> package = nullptr;
            std::vector<ClientPtr> clientVec;
            GameSingleton::serverRoot->getAllClients(clientVec);

            while (m_sendPackageQueue.try_dequeue(package))
            {
                if(clientVec.size() == 0)
                {
                    continue;
                }
                if(package != nullptr)
                {
                    packageWriter.setPosition(0);

                    packageWriter.writeUInt8(0x88);
                    packageWriter.writeUInt8(package->getID());
                    package->writeData(packageWriter);

                    comMemory.setBuffSize(packageWriter.getBuffSize());

                    // Log::Info(fmt::format("发送了 {} 的包", package->getID()));

                    uint32_t comSize = Utils::RawDeflateCompresse(packageWriter.getBuffer(), packageWriter.getPosition(), comMemory.getBuffer(), comMemory.getBuffSize());
                    if(comSize > 0)
                    {
                        packageWriter.setPosition(0);
                        packageWriter.writeUInt32(comSize);
                        packageWriter.write(comMemory.getBuffer(), comSize);

                        int32_t index;
                        switch (package->sendType)
                        {
                        case PackageSendType::TARGET:
                            {
                                ClientPtr &client = package->client;
                                if(client != nullptr)
                                {
                                    if((uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                                    {
                                        client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->sendMethod);
                                    }
                                    else
                                    {
                                        Log::Warn(fmt::format("{} 的状态为 {}, 不够包 {} 所需要的最小状态", client->getAddress(), (uint8_t)client->state, (uint8_t)package->getID()));
                                    }
                                }
                                else
                                {
                                    Log::Warn(fmt::format("包 {} 的 Client 不能为 nullptr", package->getID()));
                                }
                            }
                            break;
                        case PackageSendType::EXCEPT:
                            for(ClientPtr &client : clientVec)
                            {
                                if(client != package->client && (uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                                {
                                    client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->sendMethod);
                                }
                            }
                            break;
                        case PackageSendType::ALL:
                            for(ClientPtr &client : clientVec)
                            {
                                if((uint8_t)client->state >= (uint8_t)package->getMinNeedState())
                                {
                                    client->send(packageWriter.getBuffer(), packageWriter.getPosition(), package->sendMethod);
                                }
                            }
                            break;
                        }
                    }
                    else
                    {
                        Log::Warn(fmt::format("SendQueuePackage 数据包压缩错误 : {}", package->getID()));
                    }
                }
            }
        }
        catch(const std::exception &ex)
        {
            Log::Error(fmt::format("SendQueuePackage发生错误 : {}", ex.what()), Log::LogType::NET);
        }
    }




    void PackageManager::registerOrReplacePackageHandle(std::shared_ptr<IPackage> packageHandle)
    {
        uint8_t index = packageHandle->getID();
        if(basePackages[index] != nullptr)
        {
            Log::Info(fmt::format("替换了数据包 : {}", index));
        }
        basePackages[index] = packageHandle;
    }



    void PackageManager::registerOrReplaceFastPackageHandle(std::shared_ptr<IFastPackage> fastPackageHandle)
    {
        uint8_t index = fastPackageHandle->getID();
        if(baseFastPackages[index] != nullptr)
        {
            Log::Info(fmt::format("替换了快捷数据包 : {}", index));
        }
        baseFastPackages[index] = fastPackageHandle;
    }



    void PackageManager::load() {}
    void PackageManager::save() {}

}